home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-02-21 | 94.0 KB | 2,556 lines | [TEXT/PJMM] |
- unit UProcessGuts;
-
- {-------------------------------------------------------------------------------}
- {#}
- {# Apple Macintosh Developer Technical Support}
- {#}
- {# Interfaces for the guts of the ProcDoggie application}
- {#}
- {# Program: ProcDoggie}
- {# File: UProcessGuts.p - Pascal Implementation}
- {#}
- {# by: Forrest Tanaka}
- {#}
- {# Copyright © 1988-1991 Apple Computer, Inc.}
- {# All rights reserved.}
- {#}
- {--------------------------------------------------------------------------------}
- {#}
- {# Process Manager-related code that’s specific to ProcDoggie is contained in}
- {# this unit. Mainly, this code handles the user interface aspects of this}
- {# program that relate to the Process Manager, such as the Process List window,}
- {# the Process Information windows, and most of the menus.}
- {#}
- {# The Process List window displays a list of all active processes. It allows}
- {# the user to click on one or more of the process names and then use menu}
- {# commands to operate on those selected processes.}
- {#}
- {# Process Information windows display information about the selected active}
- {# processes. The information includes the process’s name, type, creator, SIZE}
- {# resource flags, partition size, and free memory availability.}
- {#}
- {# When the user chooses to launch an application, routines in this unit are}
- {# called to ask the user what process to launch and optionally what documents}
- {# to open or print, depending on the current launch mode.}
- {#}
- {# This unit also maintains the current launch mode. The launch mode indicates}
- {# whether the user wants to simply launch an application, launch an application}
- {# along with documents to open, and launch an application with documents to}
- {# print. The launch mode is global for this application, and affects the way}
- {# the menu commands that launch applications work.}
- {#}
- {-------------------------------------------------------------------------------}
- {[j=20/57/1$] Pasmat Options}
-
- {-------------------------------------------------------------------------------}
- {#}
- {# 2/21/91 pvh - THINK Pascal conversion.}
- {# Notes:}
- {# Slammed contents of UMenuHandler.p in here as well. THINK P doesn't handle cyclic references well.}
- {#}
- {-------------------------------------------------------------------------------}
-
- interface
-
-
- (*******************************************************************************}
- {* Units}
- {*******************************************************************************)
-
- uses
- (* Group 1 *)
- Types, QuickDraw,
-
- (* Group 2 *)
- AppleTalk, PPCToolBox, OSUtils, Files, Processes, EPPC, Notification, AppleEvents, Controls, Errors, Events, GestaltEqu, Memory, Menus, Resources, SegLoad, SysEqu, ToolUtils,
-
- (* Group 3 *)
- Aliases, Lists, Script, Windows,
-
- (* Group 4 *)
- Dialogs, Palettes, StandardFile,
-
- (* Group 5 *)
- Packages, TextEdit,
-
- (* Application *)
- UGlobals, UDialogUtils, UEmergMem, UProcessUtils,{ UMenuHandler,}
- UProcessLDEF;
-
-
- (*******************************************************************************}
- {* SetLaunchMode - Set the launch mode}
- {*}
- {* This routine is called to set the launching mode to the mode specified by the}
- {* "newMode" parameter. A launch mode of "kJustLaunch" simply launches an}
- {* application or desk accessory, "kOpenLaunch" launches an application with one}
- {* or more documents for the launched application to open, "kPrintLaunch"}
- {* launches an application with one or more documents for the launched}
- {* application to print. The launch modes are declared in UProcessUtils.p.}
- {*******************************************************************************)
-
- procedure SetLaunchMode (newMode: LaunchModeCode);
-
-
- (*******************************************************************************}
- {* GetLaunchMode - Get the launch mode}
- {*}
- {* The current launch mode is returned. For details about launching modes, see}
- {* the description of the SetLaunchMode routine.}
- {*******************************************************************************)
-
- function GetLaunchMode: LaunchModeCode;
-
-
- (*******************************************************************************}
- {* IsProcessListWindow - Is a WindowPtr a pointer to a process list window?}
- {*}
- {* When I want to find out whether a window that I have a pointer to is a process}
- {* list window or not, I call this routine. It returns TRUE if aWindow is a}
- {* pointer to a process list window, FALSE if it isn’t. If aWindow is NIL, then}
- {* IsProcessListWindow returns FALSE.}
- {*******************************************************************************)
-
- function IsProcessListWindow (aWindow: WindowPtr): Boolean;
-
-
- (*******************************************************************************}
- {* CreateProcessListWindow - Create a process list window}
- {*}
- {* This routine is called to create a new Process List window visible and}
- {* centered on the main screen. A pointer to the window is returned. If there}
- {* isn’t enough memory for the window, or if some other problem happened to make}
- {* it impossible to create the window, then CreateProcessListWindow puts up an}
- {* alert indicating this to the user, and then it returns NIL.}
- {*******************************************************************************)
-
- function CreateProcessListWindow: WindowPtr;
-
-
- (*******************************************************************************}
- {* IdleProcessListWindow - Keep the process list window up to date}
- {*}
- {* IdleProcessListWindow updates the process list window specified by}
- {* processListWindow so that it reflects the status of the processes that are}
- {* currently open. It’s called once per main event loop iteration.}
- {*******************************************************************************)
-
- procedure IdleProcessListWindow (processListWindow: WindowPtr);
-
-
- (*******************************************************************************}
- {* DrawProcessListWindow - Draw the contents of the process list window}
- {*}
- {* Whenever an update event is received for the process list window, the routine}
- {* is called to draw into the window. Since the process list covers the entire}
- {* window, the only thing to be done is to call the List Manager to draw the}
- {* list. processListWindow is a pointer to the process list window.}
- {*******************************************************************************)
-
- procedure DrawProcessListWindow (processListWindow: WindowPtr);
-
-
- (*******************************************************************************}
- {* ClickProcessListWindow - Handle a mouse click in the process list window}
- {*}
- {* When a mouse click is detected in the content region of the process list}
- {* window specified by processListWindow, this routine is called to handle it.}
- {* It allows the user to select a process or several processes in the list. If}
- {* the user double-clicks on a process, then that process and any other selected}
- {* processes are brought to the front.}
- {*}
- {* clickEvent is the mouse-down event that was in the process list window.}
- {*******************************************************************************)
-
- procedure ClickProcessListWindow (processListWindow: WindowPtr; clickEvent: EventRecord);
-
-
- (*******************************************************************************}
- {* ActivateProcessListWindow - Handle an activate/deactivate event}
- {*}
- {* Whenever an activate or deactivate event is received for the process list}
- {* window specified by processListWindow, this routine is called to handle the}
- {* event. If the event was an activate event, then becomingActive is TRUE. If}
- {* the event was a deactivate event, then becomingActive is FALSE.}
- {*******************************************************************************)
-
- procedure ActivateProcessListWindow (processListWindow: WindowPtr; becomingActive: Boolean);
-
-
- (*******************************************************************************}
- {* FixProcessListMenus - Undim menu items for process list window}
- {*}
- {* Any menus that should be available when the process list window is in front}
- {* are undimmed if the current conditions are appropriate.}
- {*******************************************************************************)
-
- procedure FixProcessListMenus (processListWindow: WindowPtr);
-
-
- (*******************************************************************************}
- {* IsProcessInfoWindow - Is a WindowPtr a pointer to a process info window?}
- {*}
- {* When I want to find out whether a window that I have a pointer to is a process}
- {* info window or not, I call this routine. It returns TRUE if aWindow is a}
- {* pointer to a process info window, FALSE if it isn’t. If aWindow is NIL, then}
- {* IsProcessInfoWindow returns NIL.}
- {*******************************************************************************)
-
- function IsProcessInfoWindow (aWindow: WindowPtr): Boolean;
-
-
- (*******************************************************************************}
- {* IdleProcessInfoWindow - Give the specified process info window some idle time}
- {*}
- {* This routine is called once per event loop iteration. It gives the specified}
- {* process info window some idle time to update the memory indicator.}
- {*******************************************************************************)
-
- procedure IdleProcessInfoWindow (processInfoWindow: WindowPtr);
-
-
- (*******************************************************************************}
- {* DrawProcessInfoWindow - Draw the contents of the process info window}
- {*}
- {* Whenever an update event is received for the process info window, the routine}
- {* is called to draw the static items into the window.}
- {*******************************************************************************)
-
- procedure DrawProcessInfoWindow (processInfoWindow: WindowPtr);
-
-
- (*******************************************************************************}
- {* FixProcessInfoMenus - Undim menu items for process information window}
- {*}
- {* Any menus that should be available when a process information window is in}
- {* front are undimmed if the current conditions are appropriate.}
- {*******************************************************************************)
-
- procedure FixProcessInfoMenus (processInfoWindow: WindowPtr);
-
-
- (*******************************************************************************}
- {* CloseProcessInfoWindow - Close a process info window}
- {*}
- {* The process info window specified by "processInfoWindow" is closed and all its}
- {* associated memory is deallocated.}
- {*******************************************************************************)
-
- procedure CloseProcessInfoWindow (processInfoWindow: WindowPtr);
-
-
- (*******************************************************************************}
- {* IdleAllProcessWindows - Give every open process window idle time}
- {*}
- {* IdleAllProcessWindows is called to give the process list window and all open}
- {* process info windows some idle time. This routine is called once per main}
- {* event loop iteration.}
- {*******************************************************************************)
-
- procedure IdleAllProcessWindows;
-
-
- (*******************************************************************************}
- {* DoLaunchInFront - Launch a process to the front}
- {*}
- {* When the user wants to launch a process and have it brought to the front, this}
- {* routine is called. It allows the user to choose a process through Standard}
- {* File. That application is then launched and brought to the front.}
- {*******************************************************************************)
-
- procedure DoLaunchInFront;
-
-
- (*******************************************************************************}
- {* DoLaunchInBack - Launch a process to the back}
- {*}
- {* When the user wants to launch a process and have it sent to the back of all of}
- {* the open processes, this routine is called. It allows the user to choose a}
- {* process through Standard File. That process is then launched and sent to the}
- {* back.}
- {*******************************************************************************)
-
- procedure DoLaunchInBack;
-
-
- (*******************************************************************************}
- {* DoLaunchTo - Launch a process and terminate self}
- {*}
- {* When the user wants to launch a process and then immediately quit ProcDoggie,}
- {* this routine is called. It allows the user to choose a process through}
- {* Standard File. That process is then launched and brought to the front, and}
- {* then ProcDoggie is immediately terminated.}
- {*******************************************************************************)
-
- procedure DoLaunchTo;
-
-
- (*******************************************************************************}
- {* DoLaunchMode - Handle Simple Launch, Open on Launch, Print on Launch commands}
- {*}
- {* This routine is called when a launch mode menu item is chosen. The launch}
- {* mode items are in the file menu and are the “Simple Launch,” “Open Documents}
- {* on Launch,” and “Print Documents on Launch” items.}
- {*******************************************************************************)
-
- procedure DoLaunchMode (modeItem: Integer);
-
-
- (*******************************************************************************}
- {* DoBringProcessToFront - Bring an open process to the front}
- {*}
- {* When the user chooses the Bring to Front menu item, this routine is called to}
- {* bring all the selected process to the front in the order that they appear in}
- {* the process list window specified by processListWindow. For the moment, it}
- {* won’t bring it’s own application (ProcDoggie) to the front. I don’t know how}
- {* or whether I’ll be able to fix that.}
- {*******************************************************************************)
-
- procedure DoBringProcessToFront (processListWindow: WindowPtr);
-
-
- (*******************************************************************************}
- {* DoGetProcessInfo - Get information about selected processes}
- {*}
- {* This routine is called when the user desires information about the processes}
- {* selected in the process list window specified by the "processListWindow"}
- {* parameter.}
- {*******************************************************************************)
-
- procedure DoGetProcessInfo (processListWindow: WindowPtr);
-
-
- (*******************************************************************************}
- {* DoTerminateProcess - Terminate the selected processes}
- {*}
- {* This routine is called when the user wants to terminate the processes selected}
- {* in the process list window specified by the "processListWindow" parameter.}
- {*******************************************************************************)
-
- procedure DoTerminateProcess (processListWindow: WindowPtr);
-
-
- { menu stuff }
- (*******************************************************************************}
- {* Constants}
- {*******************************************************************************)
-
- const
- mApple = 128; {Menu ID and resource ID of Apple menu}
- iAbout = 1; {Menu item number of About SevenPaint item}
-
- mFile = 129; {Menu ID and resource ID of File menu}
- iLaunchFore = 1; {Menu item number of Launch to Foreground… item}
- iLaunchBack = 2; {Menu item number of Launch to Background… item}
- iLaunchTo = 3; {Menu item number of Launch To… item}
- iJustLaunch = 5; {Menu item number of Simple Launch item}
- iOpenLaunch = 6; {Menu item number of Open Documents on Launch item}
- iPrintLaunch = 7; {Menu item number of Print Documents on Launch item}
- iQuit = 9; {Menu item number of Quit item}
-
- mProcess = 130; {Menu ID and resource ID of Process menu}
- iBringFront = 1; {Menu item number of Bring Process to Front item}
- iShowProcessInfo = 2; {Menu item number of Show Process Info item}
- iTerminateProcess = 3; {Menu item number of Terminate Process item}
-
-
- (*******************************************************************************}
- {* StartMenus - Do additional initialization of the menus}
- {*}
- {* This routine is called just after calling the Utilities sample code routine,}
- {* StandardMenuSetup. This application needs to do just a little bit of}
- {* additional initialization for menus. See UMenuHandler.inc1.p for details.}
- {*}
- {* If there isn’t enough memory to load the menus, then the gError global is set}
- {* to memFullErr. If desired menu resources couldn’t be found, then gError is}
- {* set to resNotFound. If any other error occurs, then gError is set to}
- {* dsSysErr.}
- {*******************************************************************************)
-
- procedure StartMenus;
-
-
- (*******************************************************************************}
- {* DoMenuChoice - Dispatch to the appropriate routine for a menu choice}
- {*}
- {* When it’s determined that a menu item was chosen, this routine is called to}
- {* dispatch to the appropriate routine for the chosen menu item. The menu item}
- {* and menu number returned by MenuSelect and MenuKey is passed in the menuChoice}
- {* parameter.}
- {*******************************************************************************)
-
- procedure DoMenuChoice (menuChoice: LongInt);
-
-
- (*******************************************************************************}
- {* FixMenus - Fix menus so that proper items are enabled and marked}
- {*}
- {* FixMenus is called to assure that menu items are disable, enabled, marked, and}
- {* unmarked appropriately. It’s called at the end of every iteration of the main}
- {* event loop.}
- {*******************************************************************************)
-
- procedure FixMenus;
-
- implementation
-
- const
- rProcessListWindID = 128; {Resource ID of process list window template}
- rProcessInfoWindID = 129; {Resource ID of process info window template}
- rProcessInfoDitlID = 129; {Resource ID of process info dialog item list}
-
- kProcessListWindKind = 8; {In windowKind field of process list windows}
- kProcessInfoWindKind = 9; {In windowKind field of process info windows}
- kActivateList = TRUE; {Pass to LActivate to specify activate list}
- kScrollBarWidth = 16; {Width of scroll bar in pixels}
-
- rAppOrDAStringID = 128; {Resource ID of Application or DA string}
- kAppStringInd = 1; {Index for Application string}
- kDAStringInd = 2; {Index for Desk Accessory string}
-
- rCheckMarkID = 128; {Resource ID of checkmark string}
-
- kProcessNameItem = 1; {Dialog item # of process name}
- kAppOrDAItem = 2; {Dialog item # of Application/DA string}
- kTotalSizeItem = 5; {Dialog item # of Total Size readout}
- kFreeSpaceItem = 6; {Dialog item # of Free Space readout}
- kMemIndicatorItem = 7; {Dialog item # of partition memory indicator}
- kGrayLineItem0 = 8; {Dialog item # of first gray line}
- kTypeItem = 11; {Dialog item # of TYPE item}
- kCreatorItem = 12; {Dialog item # of Creator item}
- kGrayLineItem1 = 13; {Dialog item # of second gray line}
- kSusResChkItem = 14; {Dialog item # of suspend/resume checkmark}
- kWindActChkItem = 15; {Dialog item # of window activate checkmark}
- kGetClickChkItem = 16; {Dialog item # of Get front click checkmark}
- kAppDiedChkItem = 17; {Dialog item # of App Died checkmark}
- kStationeryChkItem = 18; {Dialog item # of Stationery checkmark}
- kCanBackChkItem = 19; {Dialog item # of Can Background checkmark}
- kOnlyBackChkItem = 20; {Dialog item # of Only Background checkmark}
- kHighLevelChkItem = 21; {Dialog item # of High-Level Evt checkmark}
- kRHighLevelChkItem = 22; {Dialog item # of Remote High-Level checkmark}
- kMultiUserChkItem = 23; {Dialog item # of Multi-user Launch checkmark}
- k32BitCleanChkItem = 24; {Dialog item # of 32-Bit Clean checkmark}
-
- kUsedColor = 2; {Process Info window palette color for used memory}
- kFreeColor = 3; {Process Info window palette color for free memory}
-
-
- (*******************************************************************************}
- {* Types}
- {*******************************************************************************)
-
- type
- {Pointer to canonical format for number strings}
- NumFormatStringPtr = ^NumFormatString;
-
- {Pointer to process serial number}
- PSNPtr = ^ProcessSerialNumber;
-
-
- (*******************************************************************************}
- {* Variables}
- {*******************************************************************************)
-
- var
- gLaunchMode: LaunchModeCode; {Open documents? Print documents?}
-
-
-
- (*******************************************************************************}
- {* for Menu Stuff}
- {*******************************************************************************)
- const
- rMenuBar = 128; {Resource ID of this application’s MBAR resource}
-
- mFirst = mFile; {Menu ID of the first non-Apple menu in the menu list}
- mLast = mProcess; {Menu ID of the last menu in the menu list}
-
-
- (*******************************************************************************}
- {* Types}
- {*******************************************************************************)
-
- type
- MenuGuide = record
- theMenu: MenuHandle; {Handle to this guide’s menu}
- enables: LongInt {Current enable flags}
- end;
-
-
- (*******************************************************************************}
- {* Variables}
- {*******************************************************************************)
-
- var
- gMenuGuides: array[mFirst..mLast] of MenuGuide;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: SetLaunchMode}
- {*}
- {* The global variable, "gLaunchMode", is set to the launch mode specified by}
- {* "newMode".}
- {*******************************************************************************)
-
- procedure SetLaunchMode (newMode: LaunchModeCode);
-
- begin
- gLaunchMode := newMode
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: GetLaunchMode}
- {*}
- {* The value of the global variable, "gLaunchMode", is returned.}
- {*******************************************************************************)
-
- function GetLaunchMode: LaunchModeCode;
-
- begin
- GetLaunchMode := gLaunchMode
- end;
-
-
- {$S Main}
- (*******************************************************************************}
- {* Public: IsProcessListWindow}
- {*}
- {* I store a unique code in the windowKind field of every window I create so that}
- {* I can identify the kind of window it is later… like now! I check to see if}
- {* the windowKind field of aWindow is kProcessListWindKind or not. If it is, I}
- {* know it’s a process list window, and so IsProcessListWindow returns TRUE.}
- {*******************************************************************************)
-
- function IsProcessListWindow (aWindow: WindowPtr): Boolean;
-
- begin
- if aWindow <> nil then
- IsProcessListWindow := WindowPeek(aWindow)^.windowKind = kProcessListWindKind
- else
- IsProcessListWindow := FALSE
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: CreateProcessListWindow}
- {*}
- {* I store the constant kProcessListWindKind into the windowKind field of the new}
- {* window. When the routine IsProcessListWindow is called, it uses this field to}
- {* identify a window as a process list window.}
- {*}
- {* See the UWindowHandler unit for code to create a new window.}
- {*******************************************************************************)
-
- function CreateProcessListWindow: WindowPtr;
-
- const
- kDrawList = TRUE; {Pass to LNew; list must be drawn immediately}
- kHasGrow = TRUE; {Pass to LNew; list has grow box}
- kHasHorzScroll = TRUE; {Pass to LNew; list has a horizontal scroll bar}
- kHasVertScroll = TRUE; {Pass to LNew; list has a vertical scroll bar}
-
- var
- aWindow: WindowPtr; {Pointer to the process list window}
- processList: ListHandle; {Handle to the list of processes}
- listRect: Rect; {Rectangle of list in window coords}
- listDimensions: Rect; {Dimensions of list in cells}
- cellSize: Point; {Size of cell in pixels}
- currFont: FontInfo; {Information about current port’s font}
-
- procedure HandleError (messageClass: Integer; messageIndex: Integer);
-
- var
- result: Integer; {Result of alert; ignored}
-
- begin
- if aWindow <> nil then
- begin
- CloseWindow(aWindow);
- DisposPtr(Ptr(aWindow))
- end;
- result := ShowStopAlert(messageClass, messageIndex);
- gError := noErr;
- CreateProcessListWindow := nil;
- EXIT(CreateProcessListWindow)
- end;
-
- begin
- aWindow := nil;
-
- (* Create the new window *)
- aWindow := CreateWindow(rProcessListWindID);
- if gError <> noErr then
- if gError = memFullErr then
- HandleError(rMemErrMessages, kMemErrProcListOpenMsg)
- else if gError = resNotFound then
- HandleError(rResErrMessages, kResErrAppDamageMsg)
- else if gError = dsSysErr then
- HandleError(rMiscErrMessages, kMiscErrUnknownMsg);
-
- (* Set up the window *)
- SetPort(aWindow);
- WindowPeek(aWindow)^.windowKind := kProcessListWindKind;
- TextFont(1);
-
- (* Create the process list *)
- GetFontInfo(currFont);(*<*)
- listRect := aWindow^.portRect;
- listRect.right := listRect.right - kScrollBarWidth + 1;
- SetRect(listDimensions, 0, 0, 1, 0);(*<*)
- cellSize.h := listRect.right - listRect.left;
- cellSize.v := currFont.ascent + currFont.descent + currFont.leading;
- processList := LNew(listRect, listDimensions, cellSize, 128, aWindow, kDrawList, not kHasGrow, not kHasHorzScroll, kHasVertScroll);
- if FailLowMemory(0) then
- HandleError(rMemErrMessages, kMemErrProcListOpenMsg);
-
- (* Make sure the list is activated *)
- LActivate(kActivateList, processList);
-
- (* Save a handle to the list in the refCon of the window *)
- SetWRefCon(aWindow, LongInt(processList));
-
- (* Set the new window as the current GrafPort and return *)
- SetPort(aWindow);
- CreateProcessListWindow := aWindow
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Private: EqualPSN - List Manager search proc}
- {*}
- {* The List Manager’s LSearch function can take a pointer to a routine that}
- {* checks to see if a record matches an entry in the list. The routine must have}
- {* an interface identical to IUMagIDString. EqualPSN is the routine that I pass}
- {* to LSearch in the IdleProcessListWindow routine. It compares the process}
- {* serial number passed in testPSN against the process serial number contained in}
- {* the ProcessListInfoRec of a cell. Because I already know the lengths of}
- {* ProcessListInfoRecs and ProcessSerialNumber records, I ignore the aLen and}
- {* bLen parameters.}
- {*}
- {* If the two process serial numbers refer to the same process, then EqualPSN}
- {* returns 0, otherwise it returns 1.}
- {*******************************************************************************)
-
- function EqualPSN (processInfo: ProcessListInfoPtr; testPSN: ProcessSerialNumberPtr; aLen: Integer; bLen: Integer): Integer;
-
- var
- equal: Boolean; {TRUE if PSNs are equal}
- error: OSErr;
-
- begin
- error := SameProcess(testPSN^, processInfo^.serialNumber, equal); (*<*)
- if equal then
- EqualPSN := 0
- else
- EqualPSN := 1
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Private: SetProcessListInfo - Set process list cell info}
- {*}
- {* SetProcessListInfo sets the cell specified by row (I’m only using one column,}
- {* so only the row matters) of the list specified by procList to the information}
- {* in procInfo. My lists contain ProcessListInfoRecs, which contain only two of}
- {* the fields in ProcessInfoRecs (process name and process serial number), so I}
- {* just copy these two fields from procInfo into listInfo. I then use LSetCell}
- {* to copy listInfo into the list.}
- {*******************************************************************************)
-
- procedure SetProcessListInfo (procInfo: ProcessInfoRec; row: Integer; procList: ListHandle);
-
- var
- listInfo: ProcessListInfoRec; {Process info from List Mgr list}
- newCell: Cell; {Cell in which to set information}
- result: Integer; {Result of alert; ignored}
-
- begin
- (* Copy the process name *)
- BlockMove(Ptr(procInfo.processName), @listInfo.processName, ORD(procInfo.processName^[0]) + 1);
-
- (* Copy the process serial number *)
- listInfo.serialNumber := procInfo.processNumber;
-
- (* Set the specified cell to the new ProcessListInfoRec *)
- newCell.h := 0;
- newCell.v := row;
- LSetCell(Ptr(@listInfo), SIZEOF(ProcessListInfoRec), newCell, procList)
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: IdleProcessListWindow}
- {*}
- {* I’m using a simple algorithm to keep the process list window’s process list}
- {* updated to the Process Manager’s process list, but it’ll probably be tough to}
- {* describe. Here goes. . .}
- {*}
- {* I compare the process serial number of each entry in the Process Manager’s}
- {* list against the process serial number of the corresponding entry in}
- {* the process list window’s list. If they match, then I just go on to the next}
- {* entries of the lists. If they don’t match, then I search the window’s list in}
- {* case the matching process is farther down. If I do find it farther down, then}
- {* I assume that the processes in the window’s list that come between the}
- {* matching entries in the two lists were deleted. So, I delete those rows. If}
- {* I don’t find it farther down, then I assume that the entry is new. I then}
- {* insert a new row in the corresponding position of the window’s list and copy}
- {* the process information to it.}
- {*}
- {* If I run out of rows in the window’s list before getting through the entire}
- {* Process Manager list, then I just keep adding new rows to the end of the}
- {* window’s list and copying over the balance.}
- {*}
- {* If I go through the entire Process Manager list but there are left-over}
- {* entries in the window’s list, then I just delete those left-overs.}
- {*}
- {* So, that’s the algorithm. It was the most efficient one I could come up with}
- {* that wasn’t even harder to explain. Beware: some parts of this routine have}
- {* only gotten minimal testing, so I wouldn’t be surprised if you find bugs.}
- {*******************************************************************************)
-
- procedure IdleProcessListWindow (processListWindow: WindowPtr);
-
- var
- procNum: ProcessSerialNumber; {Serial number of open processes}
- procInfo: ProcessInfoRec; {Process info from Proc Mgr list}
- procName: Str31; {Name of the process}
- listInfo: ProcessListInfoRec; {Process info from List Mgr list}
- listInfoLength: Integer; {Size of ProcessListInfoRec}
- currCell: Cell; {List cell being checked}
- matchCell: Cell; {Cell with matching PSN}
- procList: ListHandle; {Handle to List Mgr process list}
- foundMatch: Boolean; {Found matching List Mgr entry}
- equal: Boolean; {Proc and List Mgr elements match}
- result: Integer; {Result of alert; ignored}
- addedProcess: Boolean; {TRUE if a process added to list}
- error: OSErr;
-
- begin
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon(processListWindow));
-
- (* Start checking from start of List Mgr and Process Mgr lists *)
- addedProcess := FALSE;
- currCell.v := 0;
- currCell.h := 0;
- procNum.highLongOfPSN := 0;
- procNum.lowLongOfPSN := kNoProcess;
-
- (* Keep looping through each open process *)
- while GetNextProcess(procNum) = noErr do(*◊*)
- begin
- (* Get information about an open process *)
- procInfo.processInfoLength := SIZEOF(ProcessInfoRec);
- procInfo.processName := @procName;
- procInfo.processAppSpec := nil;
- error := GetProcessInformation(procNum, procInfo); (*◊*)
-
- (* Cmp List Mgr & Proc Mgr lists if enuf cells for # of processes *)
- if PtInRect(currCell, procList^^.dataBounds) then
- begin
- (* Get process info from List Mgr list *)
- listInfoLength := SIZEOF(ProcessListInfoRec);
- LGetCell(@listInfo, listInfoLength, currCell, procList);(*<*)
- (*◊*)
-
- (* If Proc & List Mgr lists differ, update List Mgr list *)
- error := SameProcess(procInfo.processNumber, listInfo.serialNumber, equal); (*<*)
- if not equal then
- begin
- (* See if matching process farther down List Mgr list *)
- matchCell := currCell;
- foundMatch := LSearch(@procInfo.processNumber, SIZEOF(ProcessSerialNumber), @EqualPSN, matchCell, procList);
- (*◊*)
-
- (* Was there a match farther down the List Mgr list? *)
- if foundMatch then
- (* Yes, delete intervening cells *)
- LDelRow(matchCell.v - currCell.v, currCell.v, procList)
- else
- (* No, insert the new process into List Mgr list *)
- begin
- currCell.v := LAddRow(1, currCell.v, procList);
- SetProcessListInfo(procInfo, currCell.v, procList)
- end
- end
- end
- else
- begin
- (* Ran out of rows, add one *)
- currCell.v := LAddRow(1, currCell.v, procList);
- addedProcess := TRUE;
-
- (* Set the new row to the new process information *)
- SetProcessListInfo(procInfo, currCell.v, procList)
- end;
-
- (* Go to the next cell element in List Mgr list *)
- currCell.v := SUCC(currCell.v)
- end;
-
- (* Delete any extraneous cells *)
- if currCell.v < procList^^.dataBounds.bottom then
- LDelRow(procList^^.dataBounds.bottom - currCell.v, currCell.v, procList);
-
- (* If added processes to the list and memory low, warn *)
- if addedProcess and FailLowMemory(0) then
- result := ShowCautionOKAlert(rMemErrMessages, kMemErrLowMemWarnMsg)
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: DrawProcessListWindow}
- {*}
- {* Not much here to explain.}
- {*******************************************************************************)
-
- procedure DrawProcessListWindow (processListWindow: WindowPtr);
-
- var
- procList: ListHandle; {Handle to List Mgr process list}
-
- begin
- SetPort(processListWindow);
-
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon(processListWindow));
-
- (* Update the list *)
- TextFont(1);
- TextFace([]);
- TextSize(GetDefFontSize);
- EraseRect(processListWindow^.portRect);
- LUpdate(processListWindow^.visRgn, procList);
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: ClickProcessListWindow}
- {*}
- {* The List Manager is doing the lion’s share of the work.}
- {*******************************************************************************)
-
- procedure ClickProcessListWindow (processListWindow: WindowPtr; clickEvent: EventRecord);
-
- var
- procList: ListHandle; {Handle to List Mgr process list}
- clickPos: Point; {Position of mouse click in window coords}
- doubleClick: Boolean; {TRUE if cell was double-clicked}
-
- begin
- SetPort(processListWindow);
-
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon(processListWindow));
-
- (* Call the List Manager to handle the click *)
- clickPos := clickEvent.where;
- GlobalToLocal(clickPos);(*◊*)
- doubleClick := LClick(clickPos, clickEvent.modifiers, procList);
- if doubleClick then
- DoBringProcessToFront(processListWindow);
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: ActivateProcessListWindow}
- {*}
- {* The List Manager is called to activate/deactivate the process list window.}
- {*******************************************************************************)
-
- procedure ActivateProcessListWindow (processListWindow: WindowPtr; becomingActive: Boolean);
-
- var
- procList: ListHandle; {Handle to List Mgr process list}
-
- begin
- SetPort(processListWindow);
-
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon(processListWindow));
-
- (* Call the List Manager to activate or deactivate the list *)
- LActivate(becomingActive, procList)
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: FixProcessListMenus}
- {*}
- {* The three launching items in the File menu are enabled as long as there’s}
- {* enough memory available.}
- {*}
- {* The List Manager routine, LGetSelect, is called to see if there are any}
- {* processes in the Process List window specified by the "processListWindow"}
- {* parameter that are selected. If there are, then the three items in the}
- {* Process menu are enabled. If there isn’t enough memory to safely work in,}
- {* then only the Bring Process to Front is enabled.}
- {*******************************************************************************)
-
- procedure FixProcessListMenus (processListWindow: WindowPtr);
-
- const
- kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
-
- var
- aMenu: MenuHandle; {Handle to any menu we’re checking on}
- procList: ListHandle; {Handle to List Mgr process list}
- aCell: Cell; {Cell of process list}
-
- begin
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon(processListWindow));
-
- (* Enable the File menu launch items *)
- aMenu := GetMHandle(mFile);
- if not FailLowMemory(0) then
- begin
- EnableItem(aMenu, iLaunchFore);
- EnableItem(aMenu, iLaunchBack);
- EnableItem(aMenu, iLaunchTo)
- end;
-
- (* Undim the Process menu items *)
- aMenu := GetMHandle(mProcess);
- aCell.v := 0;
- aCell.h := 0;
- if LGetSelect(kFindNext, aCell, procList) then (*◊*)
- begin
- (* There’s ≥ 1 sel’d process, enable Bring Process to Front *)
- EnableItem(aMenu, iBringFront);
-
- (* Only enable other two items if enough memory to safely work *)
- if not FailLowMemory(0) then
- begin
- EnableItem(aMenu, iShowProcessInfo);
- EnableItem(aMenu, iTerminateProcess)
- end
- end
- end;
-
-
- {$S Main}
- (*******************************************************************************}
- {* Public: IsProcessInfoWindow}
- {*}
- {* I store a unique code in the windowKind field of every window I create so that}
- {* I can identify the kind of window it is later… like now! I check to see if}
- {* the windowKind field of aWindow is kProcessInfoWindKind or not. If it is, I}
- {* know it’s a process info window, and so IsProcessInfoWindow returns TRUE.}
- {*******************************************************************************)
-
- function IsProcessInfoWindow (aWindow: WindowPtr): Boolean;
-
- begin
- if aWindow <> nil then
- IsProcessInfoWindow := WindowPeek(aWindow)^.windowKind = kProcessInfoWindKind
- else
- IsProcessInfoWindow := FALSE
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Private: GetNumberParts - Get the default number parts table}
- {*}
- {* To use the Script Manager’s number conversion routines, the number parts table}
- {* in the 'itl4' resource must be retrieved. This routine gets the itl4 resource}
- {* and copies the number parts table into the "partsTable" parameter.}
- {*}
- {* If the retrieval was successful, then TRUE is returned. If the itl4 resource}
- {* couldn’t be loaded for some reason, then FALSE is returned.}
- {*******************************************************************************)
-
- function GetNumberParts (var partsTable: NumberParts): Boolean;
-
- var
- intl4: Itl4Handle; {Handle to the itl4 resource}
-
- begin
- intl4 := Itl4Handle(IUGetIntl(4));
- if intl4 <> nil then
- begin
- partsTable := NumberPartsPtr(ORD(intl4^) + intl4^^.defPartsOffset)^;
- GetNumberParts := TRUE
- end
- else
- GetNumberParts := FALSE
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Private: TextLineBox - Draw a line of text into a box.}
- {*}
- {* This routine is very similar to TextEdit’s TextBox routine, and in fact it}
- {* takes the same parameters. But TextLineBox draws a single line of text}
- {* specified by "textLine" and having the length specified by "length" into}
- {* the current GrafPort, ignoring carriage returns and word-wrap. This means}
- {* that there’s less overhead than TextBox. But TextBox itself is optimized for}
- {* single lines of text, so there is an ulterior motive for this routine.}
- {* TextBox erases the entire box before drawing the text. This results in a}
- {* slight flicker if TextBox is called to draw over previous text. TextLineBox}
- {* only erases the part of the box that isn’t covered with the text specified by}
- {* "textLine". Also, the text is drawn in srcCopy mode. If TextLineBox is}
- {* called to draw over existing text, the result should be a smooth transition}
- {* from one text to another, without flicker.}
- {*******************************************************************************)
-
- procedure TextLineBox (textLine: Ptr; length: Integer; box: Rect; just: Integer);
-
- var
- currPort: GrafPtr; {Pointer to the current GrafPort}
- currTextMode: Integer; {Current text mode}
- currFont: FontInfo; {Current font information}
- lineWidth: Integer; {Width of line of text in pixels}
- spareSpace: Integer; {Width of box - width of text}
- spareRect: Rect; {Rectangle of area not filled with text}
- currClip: RgnHandle; {Handle to the current clip region}
-
- begin
- (* Save the current clip region and set the clip region to "box" *)
- currClip := NewRgn;
- GetClip(currClip);(*<*)
- ClipRect(box);
-
- (* Save the current text mode and set it to srcCopy *)
- GetPort(currPort);(*<*)
- currTextMode := currPort^.txMode;
- TextMode(srcCopy);
-
- (* If default justification, set to real justification based on SysJust *)
- if just = teFlushDefault then
- if GetSysJust = 0 then
- just := teFlushLeft
- else
- just := teFlushRight;
-
- (* Move pen to baseline on left side of box *)
- GetFontInfo(currFont);
- MoveTo(box.left, box.top + currFont.ascent);
-
- (* Find the width of the specified text *)
- lineWidth := TextWidth(textLine, 0, length);
-
- (* Adjust the pen for centered or right-aligned text *)
- if just <> teFlushLeft then
- begin
- spareSpace := box.right - box.left - lineWidth;
- if just = teCenter then
- spareSpace := spareSpace div 2;
- Move(spareSpace, 0);
- end;
-
- (* Erase area at end(s) of text *)
- spareRect := box;
- if just = teFlushLeft then
- spareRect.left := spareRect.left + lineWidth
- else
- begin
- if just = teCenter then
- begin
- spareRect.left := spareRect.left + spareSpace + lineWidth;
- EraseRect(spareRect)
- end;
- spareRect.left := box.left;
- spareRect.right := spareRect.left + spareSpace;
- end;
- if not EmptyRect(spareRect) then
- EraseRect(spareRect);
-
- (* Draw the line of text *)
- DrawText(textLine, 0, length);
-
- (* Restore the port to its normal state *)
- TextMode(currTextMode);
- SetClip(currClip);
- DisposeRgn(currClip)
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Private: FindProcessInfoWindow - Find a process info window for a process}
- {*}
- {* This routine searches the window list for a process info window that}
- {* represents the process with the process serial number specified by}
- {* "searchPSN". Every process info window has a handle to the process serial}
- {* number of the process it represents in the refCon field of the window. The}
- {* Process Manager routine, SameProcess, does the work of comparing the given}
- {* process serial number against the process serial number in the refCon.}
- {*}
- {* If a window for the specified process is found, a pointer to that window is}
- {* returned. If there isn’t any window representing the given process, then NIL}
- {* is returned.}
- {*******************************************************************************)
-
- function FindProcessInfoWindow (searchPSN: ProcessSerialNumber): WindowPtr;
-
- var
- testWindow: WindowPtr; {Pointer to window we’re testing}
- found: Boolean; {TRUE if matching process info window was found}
- psnHandle: Handle; {Handle to PSN of window’s process info window}
- error: OSErr;
-
- begin
- found := FALSE;
- testWindow := FrontWindow;
-
- (* Loop until the window is found or every window has been searched *)
- while (testWindow <> nil) and (not found) do
- begin
- if IsProcessInfoWindow(testWindow) then
- begin
- (* Get the PSN of the window from its refCon *)
- psnHandle := Handle(GetWRefCon(testWindow));
-
- (* Compare window’s PSN against searchPSN *)
- HLock(psnHandle);
- error := SameProcess(searchPSN, PSNPtr(psnHandle^)^, found);
- (*<*)
- HUnlock(psnHandle)
- end;
-
- (* Go to the next window in the window list *)
- if not found then
- testWindow := WindowPtr(WindowPeek(testWindow)^.nextWindow)
- end;
-
- (* Return pointer to matching process info window, or NIL if no match *)
- FindProcessInfoWindow := testWindow
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Private: CreateProcessInfoWindow - Create a process info window}
- {*}
- {* This routine is called to create a new process info window and to display it}
- {* on the screen. A pointer to the window is returned. If there wasn’t enough}
- {* memory to open the new window, or if there was some other problem preventing}
- {* the window from being completely created, then an alert indicating the problem}
- {* is presented to the user and NIL is returned.}
- {*}
- {* I store the constant kProcessInfoWindKind into the windowKind field of the new}
- {* window. When the routine IsProcessInfoWindow is called, it uses this field to}
- {* identify a window as a process info window.}
- {*******************************************************************************)
-
- function CreateProcessInfoWindow: WindowPtr;
-
- var
- aWindow: WindowPtr; {Pointer to the new window}
- error: OSErr;
-
- procedure HandleError (messageClass: Integer; messageIndex: Integer);
-
- var
- result: Integer; {Result of alert; ignored}
-
- begin
- if aWindow <> nil then
- CloseProcessInfoWindow(aWindow);
- result := ShowStopAlert(messageClass, messageIndex);
- gError := noErr;
- CreateProcessInfoWindow := nil;
- EXIT(CreateProcessInfoWindow)
- end;
-
- begin
- aWindow := nil;
-
- (* Create the new window *)
- aWindow := CreateDialog(rProcessInfoWindID);
- if aWindow = nil then
- if gError = memFullErr then
- HandleError(rMemErrMessages, kMemErrProcInfoOpenMsg)
- else if gError = resNotFound then
- HandleError(rResErrMessages, kResErrAppDamageMsg)
- else if gError = dsSysErr then
- HandleError(rMiscErrMessages, kMiscErrUnknownMsg);
-
- (* Set up the window *)
- SetPort(aWindow);
- WindowPeek(aWindow)^.windowKind := kProcessInfoWindKind;
-
- (* Install the dialog items *)
- error := InstallDialogItems(aWindow, rProcessInfoDitlID);
- if error <> noErr then
- if error = memFullErr then
- HandleError(rMemErrMessages, kMemErrProcInfoOpenMsg)
- else if error = resNotFound then
- HandleError(rResErrMessages, kResErrAppDamageMsg)
- else if error = dsSysErr then
- HandleError(rMiscErrMessages, kMiscErrUnknownMsg);
-
- CreateProcessInfoWindow := aWindow
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Private: DrawGrayLine - Draw a gray line into a dialog item}
- {*}
- {* DrawGrayLine draws a line from the top-left corner of "grayLineRect" to its}
- {* bottom-right corner. On a non-Color QuickDraw Macintosh, this line is simply}
- {* drawn using the 50% gray pattern. On a Color QuickDraw Macintosh, a gray}
- {* type-2 pattern is created with a gray color. When this pattern is used to}
- {* draw to the screen, it is drawn using the specified color if possible. If}
- {* there aren’t enough available colors, the color is dithered using the closest}
- {* available colors.}
- {*******************************************************************************)
-
- procedure DrawGrayLine (grayLineRect: Rect);
-
- var
- qdVersion: LongInt; {QuickDraw version number}
- grayColor: RGBColor; {Color of gray line}
- grayPattern: PixPatHandle; {Handle to the gray pattern}
- result: OSErr;
-
- begin
- grayPattern := nil;
- PenNormal;
-
- (* See if Color QuickDraw is on this machine or not *)
- result := Gestalt(gestaltQuickdrawVersion, qdVersion); (*<*)
- if qdVersion = gestaltOriginalQD then
- (* Nope, just draw a 50% gray pattern *)
- PenPat(gray)
- else
- (* Yup, make a true gray pattern that can be dithered to the screen *)
- begin
- grayColor.red := $7FFF;
- grayColor.green := $7FFF;
- grayColor.blue := $7FFF;
- grayPattern := NewPixPat;
- MakeRGBPat(grayPattern, grayColor);
- PenPixPat(grayPattern);
- end;
-
- (* Draw the line *)
- MoveTo(grayLineRect.left, grayLineRect.top);
- LineTo(grayLineRect.right, grayLineRect.bottom);
-
- (* Clean up *)
- if grayPattern <> nil then
- DisposPixPat(grayPattern);
- PenNormal
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Private: SetUpProcessInfoItems - Set up process information static text items}
- {*}
- {* This routine sets up the text of the static text items in the process info}
- {* window specified by "processInfoWindow" to reflect the process information}
- {* passed in the "processInfo" parameter. Only the process information that}
- {* doesn’t change while a process is active is set in this routine. Information}
- {* that changes while a process is active is set and drawn in the}
- {* IdleProcessInfoWindow routine.}
- {*}
- {* Numbers are converted to strings using the FormatX2Str routine. FormatX2Str}
- {* requires a script-independent canonical number format so that the resulting}
- {* string appears with the proper thousands separator regardless of the script}
- {* in use. I previously created a canonical number format that has the form}
- {* ###,###,### in the U.S and saved it in a resource of type NUMF.}
- {*******************************************************************************)
-
- procedure SetUpProcessInfoItems (processInfoWindow: WindowPtr; processInfo: ProcessInfoRec);
-
- var
- itemString: Str255; {"Application" or "Desk Accessory" string}
- blankString: Integer; {Dummy empty string}
- checkString: StringPtr; {Ptr either to check mark or blankString}
- checkStrHnd: StringHandle; {Handle to check mark string}
- partitionSize: extended; {Size of processes partition}
- partsTable: NumberParts; {Number parts table from itl4 resource}
- canonRsrc: Handle; {Hnd to canonical # format '###,###,###'}
- status: FormatStatus; {Status of #->String conversion}
- success: Boolean; {TRUE if GetNumberParts call worked}
-
- begin
- (* Set process name *)
- SetStatTextItem(processInfoWindow, kProcessNameItem, @processInfo.processName^[1], ORD(processInfo.processName^[0]));
-
- (* Set Application or Desk Accessory string *)
- if BAND(processInfo.processMode, modeDeskAccessory) <> 0 then
- GetIndString(itemString, rAppOrDAStringID, kDAStringInd)(*◊*)
- else
- GetIndString(itemString, rAppOrDAStringID, kAppStringInd);(*◊*)
- SetStatTextItem(processInfoWindow, kAppOrDAItem, @itemString[1], ORD(itemString[0]));
-
- (* Set partition size item *)
- partitionSize := processInfo.processSize div 1024;
- success := GetNumberParts(partsTable);
- if success then
- begin
- (* Get the canonical number format I created earlier *)
- canonRsrc := Get1Resource('NUMF', 0);
- if canonRsrc <> nil then
- begin
- (* Convert partition size from extended to formatted string *)
- HLock(canonRsrc);
- status := FormatX2Str(partitionSize, NumFormatStringPtr(canonRsrc^)^, partsTable, itemString);
- (*<*)
- HUnlock(canonRsrc);
-
- (* Set Total Size item to formatted partition size string *)
- SetStatTextItem(processInfoWindow, kTotalSizeItem, @itemString[1], ORD(itemString[0]))
- end
- end;
-
- (* Set type and creator *)
- SetStatTextItem(processInfoWindow, kTypeItem, @processInfo.processType, SIZEOF(LongInt));
- SetStatTextItem(processInfoWindow, kCreatorItem, @processInfo.processSignature, SIZEOF(OSType));
-
- (* Initialize the checkmark and blank strings *)
- checkStrHnd := GetString(rCheckMarkID);
- if checkStrHnd <> nil then
- BlockMove(Ptr(checkStrHnd^), @itemString, ORD(checkStrHnd^^[0]) + 1)
- else
- itemString[0] := CHR(0);
- blankString := 0;
-
- (* Check the suspend/resume flag *)
- if BAND(processInfo.processMode, modeNeedSuspendResume) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, kSusResChkItem, @checkString^[1], ORD(checkString^[0]));
-
- (* Check the window activate flag *)
- if BAND(processInfo.processMode, modeDoesActivateOnFGSwitch) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, kWindActChkItem, @checkString^[1], ORD(checkString^[0]));
-
- (* Check the window activate flag *)
- if BAND(processInfo.processMode, modeGetFrontClicks) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, kGetClickChkItem, @checkString^[1], ORD(checkString^[0]));
-
- (* Check the window activate flag *)
- if BAND(processInfo.processMode, modeGetAppDiedMsg) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, kAppDiedChkItem, @checkString^[1], ORD(checkString^[0]));
-
- (* Check the window activate flag *)
- if BAND(processInfo.processMode, modeStationeryAware) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, kStationeryChkItem, @checkString^[1], ORD(checkString^[0]));
-
- (* Check the window activate flag *)
- if BAND(processInfo.processMode, modeCanBackground) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, kCanBackChkItem, @checkString^[1], ORD(checkString^[0]));
-
- (* Check the window activate flag *)
- if BAND(processInfo.processMode, modeOnlyBackground) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, kOnlyBackChkItem, @checkString^[1], ORD(checkString^[0]));
-
- (* Check the window activate flag *)
- if BAND(processInfo.processMode, modeHighLevelEventAware) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, kHighLevelChkItem, @checkString^[1], ORD(checkString^[0]));
-
- (* Check the window activate flag *)
- if BAND(processInfo.processMode, modeLocalAndRemoteHLEvents) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, kRHighLevelChkItem, @checkString^[1], ORD(checkString^[0]));
-
- (* Check the window activate flag *)
- if BAND(processInfo.processMode, modeMultiLaunch) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, kMultiUserChkItem, @checkString^[1], ORD(checkString^[0]));
-
- (* Check the window activate flag *)
- if BAND(processInfo.processMode, mode32BitCompatible) <> 0 then
- checkString := @itemString
- else
- checkString := @blankString;
- SetStatTextItem(processInfoWindow, k32BitCleanChkItem, @checkString^[1], ORD(checkString^[0]));
-
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: IdleProcessInfoWindow}
- {*}
- {* The memory indicator and the free memory readout are updated with the current}
- {* values.}
- {*}
- {* The free memory readout is a static text item in the DITL, but there’s no text}
- {* for it. Instead, I’m drawing into that item’s rectangle using TextLineBox.}
- {* I set the item up as a static text item just so that I can specify the type}
- {* characteristics of the free memory readout from the DITL resource rather than}
- {* hard-coding them in this routine.}
- {*}
- {* Numbers are converted to strings using the FormatX2Str routine. FormatX2Str}
- {* requires a script-independent canonical number format so that the resulting}
- {* string appears with the proper thousands separator regardless of the script}
- {* in use. I previously created a canonical number format that has the form}
- {* ###,###,### in the U.S and saved it in a resource of type NUMF.}
- {*******************************************************************************)
-
- procedure IdleProcessInfoWindow (processInfoWindow: WindowPtr);
-
- var
- processInfo: ProcessInfoRec; {Process info for window’s process}
- psnHandle: Handle; {Handle to PSN of window’s process}
- freeSpace: extended; {Amount of free space in partition}
- canonRsrc: Handle; {canonical # format '###,###,###'}
- freeSpaceStr: Str255; {String representation of freeSpace}
- status: FormatStatus; {Status of #->string conversion}
- partsTable: NumberParts; {Number parts table from itl4 resource}
- itemType: TypeInfoRec; {Type information for free mem readout}
- itemRect: Rect; {Rectangle of dialog item}
- freeAngle: Integer; {Angle between free and full memory}
- aColor: RGBColor; {Color to draw memory indicator}
- qdVersion: LongInt; {Version of QuickDraw on this machine}
- success: Boolean; {TRUE if GetNumberParts call worked}
- error: OSErr;
-
- begin
- SetPort(processInfoWindow);
- PenNormal;
-
- (* Get the PSN of the process associated with processInfoWindow *)
- psnHandle := Handle(GetWRefCon(processInfoWindow));
-
- (* Get information about an open process *)
- processInfo.processInfoLength := SIZEOF(ProcessInfoRec);
- processInfo.processName := nil;
- processInfo.processAppSpec := nil;
- HLock(psnHandle);
- error := GetProcessInformation(PSNPtr(psnHandle^)^, processInfo); (*◊*)
- HUnlock(psnHandle);
-
- (* Check to see whether the process still exists *)
- if error = procNotFound then
- (* Process terminated, so close this process info window *)
- CloseProcessInfoWindow(processInfoWindow)
- else
- begin
- (* Starting here, convert amount of free space to a string *)
- freeSpace := processInfo.processFreeMem div 1024;
-
- (* Get number parts table from itl4 *)
- success := GetNumberParts(partsTable);(*<*)
- if success then
- begin
- (* Get my canonical number format *)
- canonRsrc := Get1Resource('NUMF', 0);
- if canonRsrc <> nil then
- begin
- (* Convert free space to equivalent string *)
- HLock(canonRsrc);
- status := FormatX2Str(freeSpace, NumFormatStringPtr(canonRsrc^)^, partsTable, freeSpaceStr);
- (*<*)
- HUnlock(canonRsrc);
-
- (* Get the item rectangle of the free-space readout *)
- GetDialogItemRect(processInfoWindow, kFreeSpaceItem, itemRect);
- (*<*)
-
- (* Get the font characteristics of the stat text item *)
- GetStatTextFontInfo(processInfoWindow, kFreeSpaceItem, itemType);
- (*<*)
-
- (* Draw the free-space readout *)
- TextFont(itemType.typeFace);
- TextSize(itemType.typeSize);
- TextFace(itemType.typeStyle);
- TextLineBox(@freeSpaceStr[1], ORD(freeSpaceStr[0]), itemRect, itemType.textJust)
- end;
- end;
-
- (* Draw the memory indicator frame *)
- GetDialogItemRect(processInfoWindow, kMemIndicatorItem, itemRect);
- (*<*)
- FrameOval(itemRect);
- InsetRect(itemRect, 1, 1);(*◊*)
-
- (* Calc angle in the memory indicator that the free memory begins *)
- freeAngle := processInfo.processFreeMem * 360 div processInfo.processSize;
-
- (* Draw the memory indicator *)
- error := Gestalt(gestaltQuickdrawVersion, qdVersion); (*<*)
- if qdVersion = gestaltOriginalQD then
- PenPat(black)
- else
- begin
- PmForeColor(kUsedColor);
- PmBackColor(0)
- end;
-
- (* Draw the used memory part of the memory indicator *)
- PaintArc(itemRect, 0, 360 - freeAngle);
-
- (* Set the color of the free memory part of the indicator *)
- if qdVersion = gestaltOriginalQD then
- PenPat(white)
- else
- begin
- PmForeColor(kFreeColor);
- PmBackColor(1)
- end;
-
- (* Draw the free memory part of the memory indicator *)
- PaintArc(itemRect, 360 - freeAngle, freeAngle);
-
- (* Reset the port characteristics back to normal *)
- PenNormal;
- if qdVersion <> gestaltOriginalQD then
- begin
- PmForeColor(1);
- PmBackColor(0)
- end
- end
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: DrawProcessInfoWindow}
- {*}
- {* The Dialog Utility routine, DrawDialogItems, is called to draw all the}
- {* standard dialog items in the processInfoWindow specified by processInfoWindow.}
- {* Then, the cosmetic gray lines are drawn. The memory readouts aren’t drawn}
- {* because they’re drawn in IdleProcessInfoWindow.}
- {*******************************************************************************)
-
- procedure DrawProcessInfoWindow (processInfoWindow: WindowPtr);
-
- var
- grayLineRect: Rect; {Rectangle of gray line item}
-
- begin
- (* Draw the standard dialog items *)
- DrawDialogItems(processInfoWindow);
-
- (* Draw the two gray, cosmetic, separating lines *)
- GetDialogItemRect(processInfoWindow, kGrayLineItem0, grayLineRect); (*<*)
- DrawGrayLine(grayLineRect);
- GetDialogItemRect(processInfoWindow, kGrayLineItem1, grayLineRect); (*<*)
- DrawGrayLine(grayLineRect)
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: FixProcessInfoMenus}
- {*}
- {* If there’s enough memory to work with, the launch items in the File menu are}
- {* enabled.}
- {*******************************************************************************)
-
- procedure FixProcessInfoMenus (processInfoWindow: WindowPtr);
-
- var
- aMenu: MenuHandle; {Handle to any menu we’re checking on}
-
- begin
- (* Undim the File menu items *)
- aMenu := GetMHandle(mFile);
- if not FailLowMemory(0) then
- begin
- EnableItem(aMenu, iLaunchFore);
- EnableItem(aMenu, iLaunchBack);
- EnableItem(aMenu, iLaunchTo)
- end
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: CloseProcessInfoWindow}
- {*}
- {* This should be pretty easy to figure out.}
- {*******************************************************************************)
-
- procedure CloseProcessInfoWindow (processInfoWindow: WindowPtr);
-
- var
- psnHandle: Handle; {Handle to the PSN of process the window represents}
-
- begin
- DisposHandle(Handle(GetWRefCon(processInfoWindow)));
- CloseWindow(processInfoWindow);
- DisposeDialogItems(processInfoWindow);
- DisposPtr(Ptr(processInfoWindow))
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: IdleAllProcessWindows}
- {*}
- {* The process list window and process info windows each have their own idle}
- {* routine defined in this source file, so the type of window is checked and the}
- {* appropriate idle routine is called for that window.}
- {*******************************************************************************)
-
- procedure IdleAllProcessWindows;
-
- var
- processWindow: WindowPtr; {Pointer to each process window being idled}
-
- begin
- processWindow := FrontWindow;
-
- (* Loop through all windows in the window list *)
- while processWindow <> nil do
- begin
- (* Call the appropriate idle routine if it’s a process window *)
- if IsProcessListWindow(processWindow) then
- IdleProcessListWindow(processWindow)
- else if IsProcessInfoWindow(processWindow) then
- IdleProcessInfoWindow(processWindow);
-
- (* Go to the next window in the window list *)
- processWindow := WindowPtr(WindowPeek(processWindow)^.nextWindow)
- end
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Private: AppDAFilter - File filter procedure for apps and files with DAs}
- {*}
- {* This is a Standard File file filter procedure that allows applications and}
- {* any files with desk accessories in them to show up in the Standard File file}
- {* list.}
- {*}
- {* Checking to see whether a file is an application is easy enough. Just}
- {* check to see whether its type is APPL. If it is, then it’s an application.}
- {* Checking on desk accessories is trickier. Desk accessories can be contained}
- {* in any type of file. So if a file isn’t doesn’t have the APPL type, I open}
- {* the resource fork of the file using HOpenResFile and an access mode of}
- {* fdRdPerm. This allows me to open and close the resource file without worrying}
- {* about that resource file being open by someone else because HOpenResFile with}
- {* an access mode of fdRdPerm returns a unique access path to this routine. When}
- {* the file is open, I check for DRVR resources. DRVR resources can be either}
- {* desk accessories or device drivers. I only want to show files containing desk}
- {* accessories, so I check on the first character of the DRVR resource’s name.}
- {* If it’s a null character, then the DRVR is a desk accessory. If it’s any}
- {* other character, then it’s a device driver and I ignore it.}
- {*******************************************************************************)
-
- function AppDAFilter (fileInfo: CInfoPBPtr): Boolean;
-
- const
- kShowIt = FALSE; {FALSE means I do not filter out...}
-
- type
- LongIntPtr = ^LongInt;
-
- var
- resRef: Integer; {File ref num of file being tested}
- currResRef: Integer; {File ref number of current file}
- numDrvrs: Integer; {Number of DRVR resources in file being tested}
- index: Integer; {Index into resources of file being tested}
- drvrRsrc: Handle; {Handle to DRVR resource; always NIL master ptr}
- resID: Integer; {Resource ID of DRVR resource; ignored}
- myResType: ResType; {Resource type of DRVR resource; ignored}
- resName: Str255; {Resource name of DRVR resource}
-
- begin
- if fileInfo^.ioFlFndrInfo.fdType = 'APPL' then
- AppDAFilter := kShowIt
- else
- begin
- (* Assume we don’t show the file *)
- AppDAFilter := not kShowIt;
-
- (* Want to check rsrcs, not load ’em, including preload resources *)
- SetResLoad(FALSE);
-
- (* Save current res file refnum, open the specified rsrc file *)
- currResRef := CurResFile;
- resRef := HOpenResFile(fileInfo^.ioVRefNum, LongIntPtr(CurDirStore)^, fileInfo^.ioNamePtr^, fsRdPerm);
-
- (* If couldn’t open resource file, HOpenResFile returns -1 *)
- if (resRef <> -1) then
- begin
- UseResFile(resRef);
-
- (* Count number of DRVR resources in the file *)
- numDrvrs := Count1Resources('DRVR');
- if numDrvrs > 0 then
- begin
- (* For each DRVR, see if it’s a DA *)
- for index := 1 to numDrvrs do
- begin
- drvrRsrc := Get1IndResource('DRVR', index);
- GetResInfo(drvrRsrc, resID, myResType, resName); (*<*)
- (*<*)
- (*<*)
-
- (* If first char of name is null, it’s a DA *)
- if resName[1] = CHR(0) then
- AppDAFilter := kShowIt
- end
- end;
- CloseResFile(resRef)
- end;
-
- (* Restore everything back to what it was *)
- UseResFile(currResRef);
- SetResLoad(TRUE)
- end
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Private: LaunchCycle - Attempt to launch a process}
- {*}
- {* This routine calls the LaunchProcess routine that’s in the UProcessUtils unit.}
- {* The launchFile parameter specifies the file to launch. The docList parameter}
- {* specifies the list of documents to pass to the launched application for it to}
- {* open or print. The launchOptions parameter specifies the initial set of}
- {* launch options to use when launching. The the section titled “Specifying}
- {* Launch Options” in the Process Manager chapter of Inside Macintosh VI for the}
- {* a list and description of the launch options that you can pass in this}
- {* parameter.}
- {*}
- {* If the Process Manager denies the launch, then LaunchProcess returns the}
- {* resulting error code in the LaunchError flag. If this happens and if the}
- {* error happened to be that the machine is in 32-bit addressing mode and the}
- {* application’s SIZE resource doesn’t have the 32-bit clean flag on, or if there}
- {* isn’t enough memory to launch the application or desk accessory, then an alert}
- {* is presented to the user asking if he or she wants to continue anyway. If the}
- {* user specifies that he or she does, then launch options are added to the ones}
- {* passed in the launchOptions parameter which allow 32-bit unclean applications}
- {* to launch or to allow the launch into available memory, and then LaunchProcess}
- {* is called again. This is repeated either until the application or desk}
- {* accessory is successfully launched, the user chose not to launch it, or until}
- {* an unrecoverable error occurs.}
- {*******************************************************************************)
-
- procedure LaunchCycle (launchFile: FSSpec; docList: DocListHnd; launchOptions: Integer);
-
- var
- processNum: ProcessSerialNumber; {Serial number of launched process}
- attemptLaunch: Boolean; {TRUE if continuing launch attempt}
- result: Integer; {Result of caution alert}
- launchError: OSErr; {Launch error code}
- error: OSErr;
-
- begin
- (* Repeat until successful launch or cancelled launch *)
- repeat
- (* Attempt to launch the process *)
- error := LaunchProcess(launchFile, nil, docList, launchOptions, processNum, launchError);
- (*<*)
- (*<*)
-
- (* Check for launching errors *)
- if launchError <> noErr then
- begin
- (* There was a launching error, present to user *)
- if launchError = appModeErr then
- begin
- (* Ask user if it’s OK to launch 32-bit unclean app *)
- result := ShowCautionOKCancelAlert(rMiscWrnMessages, kMiscWrnUncleanMsg);
- if result = ok then
- begin
- (* Try launch again, allowing 32-bit unclean app *)
- launchOptions := BOR(launchOptions, launchAllow24Bit);
- attemptLaunch := TRUE
- end
- else
- attemptLaunch := FALSE
- end
- else if launchError = memFullErr then
- begin
- (* Ask user if it’s OK to launch w/ < requested memory *)
- result := ShowCautionOKCancelAlert(rMiscWrnMessages, kMiscWrnLaunchMemMsg);
- if result = ok then
- begin
- (* Try launch again, with less than requested mem *)
- launchOptions := BOR(launchOptions, launchUseMinimum);
- attemptLaunch := TRUE
- end
- else
- attemptLaunch := FALSE
- end
- else
- begin
- (* Some error we don’t handle happened *)
- result := ShowStopAlert(rMiscErrMessages, kMiscErrUnknownMsg);
- attemptLaunch := FALSE
- end
- end
- else if error <> noErr then
- begin
- result := ShowStopAlert(rMiscErrMessages, kMiscErrUnknownMsg);
- attemptLaunch := FALSE
- end
- else
- attemptLaunch := FALSE
- until not attemptLaunch;
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: DoLaunchInFront}
- {*}
- {* If the user is launching with documents, then only applications are presented}
- {* to the user in the standard-file dialog. If the user only wants to launch}
- {* without any documents, then both applications and files containing desk}
- {* accessories are presented to the user.}
- {*******************************************************************************)
-
- procedure DoLaunchInFront;
-
- var
- reply: StandardFileReply; {Reply from SFGetFile}
- typeList: SFTypeList; {List of file types for SF}
- launchSpec: FSSpec; {Location of selected app/DA}
- docList: DocListHnd; {Handle to the document list}
- gettingDocs: Boolean; {True if user still getting docs}
- launchMode: LaunchModeCode; {Current launch mode}
- error: OSErr;
-
- begin
- (* Get the user’s choice for a file to launch *)
- launchMode := GetLaunchMode;
- if launchMode = kJustLaunch then
- (* Just launching, so launch applications and DAs *)
- StandardGetFile(@AppDAFilter, -1, typeList, reply) (*<*)
- else if (launchMode = kOpenLaunch) or (launchMode = kPrintLaunch) then
- begin
- (* Launching with documents, so launch applications only *)
- typeList[0] := 'APPL';
- StandardGetFile(nil, 1, typeList, reply) (*<*)
- end;
-
- if reply.sfGood then
- begin
- launchSpec := reply.sfFile;
-
- (* Check to see if documents should be opened/printed as well *)
- if (launchMode = kOpenLaunch) or (launchMode = kPrintLaunch) then
- begin
- (* Create an empty list of documents *)
- docList := CreateDocList(launchMode);
-
- (* Keep getting documents until user chooses Cancel *)
- gettingDocs := TRUE;
- while gettingDocs do
- begin
- StandardGetFile(nil, -1, typeList, reply); (*<*)
- if reply.sfGood then
- error := AddToDocList(reply.sfFile, docList) (*◊*)
- else
- gettingDocs := FALSE
- end
- end
- else
- docList := nil;
-
- (* Attempt to launch the application *)
- LaunchCycle(launchSpec, docList, launchContinue);
-
- (* Dispose of the document list, if there was one *)
- if docList <> nil then
- DisposeDocList(docList)
- end
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: DoLaunchInBack}
- {*}
- {* For the moment, I’m using SFGetFile to choose files rather than}
- {* StandardGetFile because StandardGetFile has a bug in that file filtering}
- {* doesn’t work right. This is supposed to be fixed in b2, so I’ll change this}
- {* call once that version is released. This will make the call to FSMakeFSSpec}
- {* unnecessary because StandardGetFile returns the FSSpec of the chosen file.}
- {*******************************************************************************)
-
- procedure DoLaunchInBack;
-
- var
- reply: StandardFileReply; {Reply from SFGetFile}
- typeList: SFTypeList; {List of file types to diplay in SF}
- launchSpec: FSSpec; {Location of selected application}
- docList: DocListHnd; {Handle to the document list}
- gettingDocs: Boolean; {True if user still getting docs}
- launchMode: LaunchModeCode; {Current launch mode}
- error: OSErr;
-
- begin
- (* Get the user’s choice for an application to launch *)
- typeList[0] := 'APPL';
- StandardGetFile(nil, 1, typeList, reply); (*<*)
-
- if reply.sfGood then
- begin
- (* Convert working directory and file name to FSSpec *)
- launchSpec := reply.sfFile;
-
- launchMode := GetLaunchMode;
- if (launchMode = kOpenLaunch) or (launchMode = kPrintLaunch) then
- begin
- (* Create an empty list of documents *)
- docList := CreateDocList(launchMode);
-
- (* Keep getting documents until user chooses Cancel *)
- gettingDocs := TRUE;
- while gettingDocs do
- begin
- StandardGetFile(nil, -1, typeList, reply); (*<*)
- if reply.sfGood then
- error := AddToDocList(reply.sfFile, docList) (*◊*)
- else
- gettingDocs := FALSE
- end
- end
- else
- docList := nil;
-
- (* Attempt to launch the application *)
- LaunchCycle(launchSpec, docList, launchContinue + launchDontSwitch);
-
- (* Dispose of the document list, if there was one *)
- if docList <> nil then
- DisposeDocList(docList)
- end
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: DoLaunchTo}
- {*}
- {* For the moment, I’m using SFGetFile to choose files rather than}
- {* StandardGetFile because StandardGetFile has a bug in that file filtering}
- {* doesn’t work right. This is supposed to be fixed in b2, so I’ll change this}
- {* call once that version is released. This will make the call to FSMakeFSSpec}
- {* unnecessary because StandardGetFile returns the FSSpec of the chosen file.}
- {*******************************************************************************)
-
- procedure DoLaunchTo;
-
- var
- reply: StandardFileReply; {Reply from SFGetFile}
- typeList: SFTypeList; {List of file types to diplay in SF}
- launchSpec: FSSpec; {Location of selected file}
- docList: DocListHnd; {Handle to the document list}
- gettingDocs: Boolean; {True if user still getting docs}
- launchMode: LaunchModeCode; {Current launch mode}
- error: OSErr;
-
- begin
- (* Get the user’s choice for a file to launch *)
- launchMode := GetLaunchMode;
- if launchMode = kJustLaunch then
- (* Just launching, so launch applications and DAs *)
- StandardGetFile(@AppDAFilter, -1, typeList, reply) (*<*)
- else if (launchMode = kOpenLaunch) or (launchMode = kPrintLaunch) then
- begin
- (* Launching with documents, so launch applications only *)
- typeList[0] := 'APPL';
- StandardGetFile(nil, 1, typeList, reply) (*<*)
- end;
-
- if reply.sfGood then
- begin
- (* Convert working directory and file name to FSSpec *)
- launchSpec := reply.sfFile;
-
- if (launchMode = kOpenLaunch) or (launchMode = kPrintLaunch) then
- begin
- (* Create an empty list of documents *)
- docList := CreateDocList(launchMode);
-
- (* Keep getting documents until user chooses Cancel *)
- gettingDocs := TRUE;
- while gettingDocs do
- begin
- StandardGetFile(nil, -1, typeList, reply); (*<*)
- if reply.sfGood then
- error := AddToDocList(reply.sfFile, docList) (*◊*)
- else
- gettingDocs := FALSE
- end
- end
- else
- docList := nil;
-
- (* Attempt to launch the application or DA *)
- LaunchCycle(launchSpec, docList, launchAllow24Bit);
-
- (* Dispose of the document list, if there was one *)
- if docList <> nil then
- DisposeDocList(docList)
- end
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: DoLaunchMode}
- {*}
- {* SetLaunchMode does most of the work, and there isn’t much to do.}
- {*******************************************************************************)
-
- procedure DoLaunchMode (modeItem: Integer);
-
- begin
- case modeItem of
- iJustLaunch:
- SetLaunchMode(kJustLaunch);
- iOpenLaunch:
- SetLaunchMode(kOpenLaunch);
- iPrintLaunch:
- SetLaunchMode(kPrintLaunch)
- end
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: DoBringProcessToFront}
- {*}
- {* The List Manager is called to get each selection in the process list window.}
- {* SetFrontProcess is called with the process serial number of each selected}
- {* process. They aren’t immediately brought to the front when SetFrontProcess is}
- {* called. Instead, they are scheduled to come to the front in the same order as}
- {* they were presented to SetFrontProcess. Once ProcDoggie reenters the main}
- {* event loop, the Process Manager brings each scheduled process to the front in}
- {* turn.}
- {*}
- {* At the moment, I can’t get ProcDoggie itself to be scheduled. I assume it’s}
- {* because SetFrontProcess checks to see if process serial number you passed it}
- {* is the same as the process serial number of the current process. If it is, it}
- {* doesn’t bother to schedule the process. I’m not quite sure how to work around}
- {* that.}
- {*******************************************************************************)
-
- procedure DoBringProcessToFront (processListWindow: WindowPtr);
-
- const
- kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
-
- var
- procList: ListHandle; {Handle to List Mgr process list}
- currCell: Point; {Cell that has selection}
- listInfo: ProcessListInfoRec; {Process info from List Mgr list}
- gotSelection: Boolean; {T if got sel’d cell, F if no more}
- listInfoLen: Integer; {Length of list info in bytes}
- error: OSErr;
-
- begin
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon(processListWindow));
-
- (* Keep looping until all selected processes have been brought to front *)
- currCell.v := 0;
- currCell.h := 0;
- gotSelection := TRUE;
- while gotSelection do
- begin
- gotSelection := LGetSelect(kFindNext, currCell, procList); (*◊*)
- if gotSelection then
- begin
- listInfoLen := SIZEOF(ProcessListInfoRec);
- LGetCell(Ptr(@listInfo), listInfoLen, currCell, procList); (*◊*)
- error := SetFrontProcess(listInfo.serialNumber);
- currCell.v := currCell.v + 1
- end
- end
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: DoGetProcessInfo}
- {*}
- {* This routine loops until Process Information windows for all selected}
- {* processes in the Process List window are displayed. Information for each}
- {* process in the process list is retrieved from the list itself. Then, that}
- {* process is compared against all existing Process Information windows. If a}
- {* Process Information window already exists for that process, then that window}
- {* is simply activated and DoGetProcessInfo exits. Otherwise, the Process}
- {* Manager is called to retrieve information for that process. A new Process}
- {* Information window is created, and its contents are set to the information}
- {* retrieved for the process.}
- {*******************************************************************************)
-
- procedure DoGetProcessInfo (processListWindow: WindowPtr);
-
- const
- kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
-
- var
- procList: ListHandle; {Handle to List Mgr proc list}
- currCell: Point; {Cell that has selection}
- listInfo: ProcessListInfoRec; {Proc info from List Mgr list}
- gotSelection: Boolean; {T if got sel’d cell, F if none}
- listInfoLen: Integer; {Length of list info in bytes}
- processInfo: ProcessInfoRec; {Info about selected processes}
- procName: Str31; {Name of selected processes}
- procSpec: FSSpec; {File spec of sel’d processes}
- processInfoWindow: WindowPtr; {Ptr to new process info window}
- psnHandle: Handle; {Handle to PSN of chosen proc}
- existingWindow: WindowPtr; {Proc info wind if already open}
- error: OSErr;
-
- procedure HandleError (messageClass: Integer; messageIndex: Integer);
-
- var
- result: Integer; {Result of alert; ignored}
-
- begin
- if processInfoWindow <> nil then
- CloseProcessInfoWindow(processInfoWindow);
- result := ShowStopAlert(messageClass, messageIndex);
- gError := noErr;
- EXIT(DoGetProcessInfo)
- end;
-
- begin
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon(processListWindow));
-
- (* Keep looping until all selected processes have been brought to front *)
- currCell.v := 0;
- currCell.h := 0;
- gotSelection := TRUE;
- while gotSelection do
- begin
- gotSelection := LGetSelect(kFindNext, currCell, procList); (*◊*)
- if gotSelection then
- begin
- listInfoLen := SIZEOF(ProcessListInfoRec);
- LGetCell(Ptr(@listInfo), listInfoLen, currCell, procList); (*◊*)
-
- (* See if proc info wind already exists for selected proc *)
- existingWindow := FindProcessInfoWindow(listInfo.serialNumber);
- if existingWindow <> nil then
- SelectWindow(existingWindow)
- else
- begin
- (* Get information about an open process *)
- processInfo.processInfoLength := SIZEOF(ProcessInfoRec);
- processInfo.processName := @procName;
- processInfo.processAppSpec := @procSpec;
- error := GetProcessInformation(listInfo.serialNumber, processInfo);
- (*◊*)
- if error <> noErr then
- HandleError(rMiscErrMessages, kMiscErrUnknownMsg);
-
- (* Create the process information window *)
- processInfoWindow := CreateProcessInfoWindow;
- if processInfoWindow <> nil then
- begin
- (* Put handle to PSN into refCon *)
- psnHandle := NewHandleMargin(SIZEOF(ProcessSerialNumber), kAllocApp, not kAllocClr);
- if psnHandle = nil then
- HandleError(rMemErrMessages, kMemErrProcInfoOpenMsg);
- BlockMove(Ptr(@processInfo.processNumber), psnHandle^, SIZEOF(ProcessSerialNumber));
- SetWRefCon(processInfoWindow, LongInt(psnHandle));
-
- (* Update dlog items to reflect proc info *)
- SetUpProcessInfoItems(processInfoWindow, processInfo);
- end
- else
- gotSelection := FALSE
- end;
-
- (* Go to the next cell *)
- currCell.v := currCell.v + 1
- end
- end
- end;
-
-
- {$S ProcessGuts}
- (*******************************************************************************}
- {* Public: DoTerminateProcess}
- {*}
- {* The List Manager is used to get all of the selected processes in}
- {* processListWindow. The process serial number of each of these processes is}
- {* extracted and is then used when calling TerminateProcess.}
- {*******************************************************************************)
-
- procedure DoTerminateProcess (processListWindow: WindowPtr);
-
- const
- kFindNext = TRUE; {Pass to LGetSelect to find sequence of selections}
-
- var
- procList: ListHandle; {Handle to List Mgr process list}
- currCell: Point; {Cell that has selection}
- listInfo: ProcessListInfoRec; {Process info from List Mgr list}
- listInfoLen: Integer; {Length of list info in bytes}
- gotSelection: Boolean; {T if got sel’d cell, F if none}
- error: OSErr;
-
- procedure HandleError (messageClass: Integer; messageIndex: Integer);
-
- var
- result: Integer; {Result of alert; ignored}
-
- begin
- result := ShowStopAlert(messageClass, messageIndex);
- gError := noErr;
- EXIT(DoTerminateProcess)
- end;
-
- begin
- (* Get the List Manager’s copy of the process list *)
- procList := ListHandle(GetWRefCon(processListWindow));
-
- (* Keep looping until all selected processes have been terminated *)
- currCell.v := 0;
- currCell.h := 0;
- gotSelection := TRUE;
- while gotSelection do
- begin
- gotSelection := LGetSelect(kFindNext, currCell, procList); (*◊*)
- if gotSelection then
- begin
- listInfoLen := SIZEOF(ProcessListInfoRec);
- LGetCell(Ptr(@listInfo), listInfoLen, currCell, procList); (*◊*)
-
- (* Kill the specified process *)
- error := TerminateProcess(listInfo.serialNumber);
- if error <> noErr then
- HandleError(rMiscErrMessages, kMiscErrUnknownMsg);
-
- (* Go to the next cell *)
- currCell.v := currCell.v + 1
- end
- end
- end;
-
- {$S %A5Init}
- (*******************************************************************************}
- {* Public: DoAppleMenu}
- {*}
- {* The menu guide array is initialized with the menu handles and enable flags of}
- {* all menus.}
- {*}
- {* If GetNewMBar couldn’t load the MBAR resource, then it returns NIL and the}
- {* error code is in ResError, and I can deal with the error elegantly. But, if}
- {* the GetNewMBar couldn’t load the menus themselves, then it’ll probably crash.}
- {*******************************************************************************)
-
- procedure StartMenus;
-
- var
- menuBar: Handle; {Handle to the menu bar from the MBAR resource}
- menuIndex: Integer; {Index into menu guide records}
-
- begin
- (* Load in the menu bar *)
- menuBar := GetNewMBar(rMenuBar);
- if menuBar <> nil then
- begin
- (* Set it, then dispose of it because SetMenuBar makes a copy *)
- SetMenuBar(menuBar);
- DisposHandle(menuBar);
-
- (* Add the desk accessories to the Apple menu *)
- AddResMenu(GetMHandle(mApple), 'DRVR');
-
- (* Initialize the menu guide array *)
- for menuIndex := mFile to mProcess do
- begin
- gMenuGuides[menuIndex].theMenu := GetMHandle(menuIndex);
- gMenuGuides[menuIndex].enables := gMenuGuides[menuIndex].theMenu^^.enableFlags
- end;
-
- (* Draw the menu bar *)
- DrawMenuBar
- end
- else if ResError = memFullErr then
- gError := memFullErr
- else if (ResError = noErr) or (ResError = resNotFound) then
- gError := resNotFound
- else
- gError := dsSysErr
- end;
-
-
- {$S Main}
- (*******************************************************************************}
- {* Private: DoAppleMenu - Handle an Apple menu item choice}
- {*}
- {* This routine is called whenever it’s determined that the chosen menu item was}
- {* in the Apple menu. If the chosen menu item that’s passed in the menuItem}
- {* parameter wasn’t the About item, the name of the menu item is retrieved and}
- {* then OpenDeskAcc is called with this name so that the desk accessory by that}
- {* name is opened. The Process Manager can launch desk accessories, but}
- {* OpenDeskAcc should still be used if the user chooses any item in the Apple}
- {* menu.}
- {*******************************************************************************)
-
- procedure DoAppleMenu (menuItem: Integer);
-
- var
- daName: Str255; {Name of the chosen DA}
- refNum: Integer; {Reference number of the DA, ignored}
-
- begin
- if menuItem = iAbout then
- ShowAboutBox
- else
- begin
- GetItem(GetMHandle(mApple), menuItem, daName); (*<*)
- refNum := OpenDeskAcc(daName)
- end
- end;
-
-
- {$S Main}
- (*******************************************************************************}
- {* Private: DoFileMenu - Handle a File menu item choice}
- {*}
- {* This routine is called whenever it’s determined that the chosen menu item was}
- {* in the File menu. The item number of the chosen menu item is passed in the}
- {* menuItem parameter.}
- {*******************************************************************************)
-
- procedure DoFileMenu (menuItem: Integer);
-
- begin
- case menuItem of
- iLaunchFore:
- DoLaunchInFront;
- iLaunchBack:
- DoLaunchInBack;
- iLaunchTo:
- DoLaunchTo;
- iJustLaunch, iOpenLaunch, iPrintLaunch:
- DoLaunchMode(menuItem);
- iQuit:
- DoQuit
- end
- end;
-
-
- {$S Main}
- (*******************************************************************************}
- {* Private: DoProcessMenu - Handle a Process menu item choice}
- {*}
- {* This routine is called whenever it’s determined that the chosen menu item was}
- {* in the Process menu. The item number of the chosen menu item is passed in the}
- {* menuItem parameter.}
- {*******************************************************************************)
-
- procedure DoProcessMenu (menuItem: Integer);
-
- begin
- case menuItem of
- iBringFront:
- DoBringProcessToFront(FrontWindow);
- iShowProcessInfo:
- DoGetProcessInfo(FrontWindow);
- iTerminateProcess:
- DoTerminateProcess(FrontWindow)
- end
- end;
-
-
- {$S Main}
- (*******************************************************************************}
- {* Public: DoMenuChoice}
- {*}
- {* This routine should be self-explanatory.}
- {*******************************************************************************)
-
- procedure DoMenuChoice (menuChoice: LongInt);
-
- var
- menuNum: Integer; {Menu number of chosen menu}
- menuItem: Integer; {Item number of chosen menu item}
-
- begin
- if menuChoice <> 0 then
- begin
- (* Get the chosen menu item and menu number *)
- menuNum := HiWord(menuChoice);
- menuItem := LoWord(menuChoice);
-
- (* Dispatch the appropriate menu-handling routine *)
- case menuNum of
- mApple:
- DoAppleMenu(menuItem);
- mFile:
- DoFileMenu(menuItem);
- mProcess:
- DoProcessMenu(menuItem);
- end;
- HiliteMenu(0)
- end
- end;
-
-
- {$S Main}
- (*******************************************************************************}
- {* Private: ResetMenuItems - Disable any disableable items and clear marks}
- {*}
- {* Disabling all the menu items is done bruteforcedly. It could easily be done}
- {* by looping through each menu and disabling every item that comes up (disabling}
- {* the Font menu is done this way), but I thought doing it using the brute-force}
- {* method was clearer. Then again. . .}
- {*******************************************************************************)
-
- procedure ResetMenuItems;
-
- var
- aMenu: MenuHandle; {Handle to each menu we’re disabling}
-
- begin
- (* Disable items in the File menu *)
- aMenu := GetMHandle(mFile);
- DisableItem(aMenu, iLaunchFore);
- DisableItem(aMenu, iLaunchBack);
- DisableItem(aMenu, iLaunchTo);
- SetItemMark(aMenu, iJustLaunch, CHR(noMark));
- SetItemMark(aMenu, iOpenLaunch, CHR(noMark));
- SetItemMark(aMenu, iPrintLaunch, CHR(noMark));
-
- (* Disable items in the Process menu *)
- aMenu := GetMHandle(mProcess);
- DisableItem(aMenu, iBringFront);
- DisableItem(aMenu, iShowProcessInfo);
- DisableItem(aMenu, iTerminateProcess);
- end;
-
-
- {$S Main}
- (*******************************************************************************}
- {* Public: FixMenus}
- {*}
- {* FixMenus first disables every available menu item. Then the most basic menu}
- {* items are enabled. The windowKind field of the front window is then checked.}
- {* If there is a window open, FixMenus calls a routine that’s responsible for}
- {* that kind of window to enable any menu items that are relevant to that kind of}
- {* window.}
- {*}
- {* If the front window is a modal dialog, then the basic set of menu items are}
- {* NOT enabled, and the entire Apple menu is disabled.}
- {*}
- {* After this is done, the menu bar might have to be redrawn to reflect the new}
- {* conditions. So, FixMenus go through every menu to determine if the state of}
- {* the entire menu has changed. The MenuGuide records are used to help determine}
- {* this. If the state of any many has changed, then the menu bar is redrawn.}
- {*******************************************************************************)
-
- procedure FixMenus;
-
- var
- currWindow: WindowPtr; {Pointer to the front-most window}
- currMenu: MenuHandle; {Handle to menu being enabled}
- oldEnables: LongInt; {True if 1+ menu items enabled when FixMenus called}
- newEnables: LongInt; {True if 1+ menu items enabled after menus fixed}
- mustRedraw: Boolean; {TRUE if menu bar has to be redrawn}
- numItems: Integer; {Number of items in a menu}
- menuIndex: Integer; {Index into menu guide array}
-
- begin
- (* Start by disabling all menus *)
- ResetMenuItems;
-
- (* Front-most window determines most menu enabling/disabling *)
- currWindow := FrontWindow;
-
- (* Fix the marks for the launch mode items *)
- currMenu := GetMHandle(mFile);
- case GetLaunchMode of
- kJustLaunch:
- CheckItem(currMenu, iJustLaunch, TRUE);
- kOpenLaunch:
- CheckItem(currMenu, iOpenLaunch, TRUE);
- kPrintLaunch:
- CheckItem(currMenu, iPrintLaunch, TRUE)
- end;
-
- (* Enable any window-specific menu items *)
- if currWindow <> nil then
- if IsProcessListWindow(currWindow) then
- (* Process list window in front, set up menu items in it *)
- FixProcessListMenus(currWindow)
- else if IsProcessInfoWindow(currWindow) then
- (* Process info window in front, set up menu items in it *)
- FixProcessInfoMenus(currWindow);
-
- (* Assume we don’t have to redraw the menu bar *)
- mustRedraw := FALSE;
-
- (* Check through every menu to see if there are any enabled items in it *)
- for menuIndex := mFirst to mLast do
- begin
- (* Grab the old and new enable flags excluding the flag for the entire menu *)
- oldEnables := BAnd(gMenuGuides[menuIndex].enables, $FFFFFFFE);
- newEnables := BAnd(gMenuGuides[menuIndex].theMenu^^.enableFlags, $FFFFFFFE);
-
- (* Shift left so that we only see flags for existing items *)
- numItems := CountMItems(gMenuGuides[menuIndex].theMenu);
- oldEnables := BitShift(oldEnables, 31 - numItems);
- newEnables := BitShift(newEnables, 31 - numItems);
-
- (* Determine if the menu bar must be redrawn *)
- if (oldEnables <> 0) and (newEnables = 0) then
- begin
- (* Had some items enabled, now has no items enabled, redraw *)
- DisableItem(gMenuGuides[menuIndex].theMenu, 0);
- mustRedraw := TRUE
- end
- else if (oldEnables = 0) and (newEnables <> 0) then
- begin
- (* Had no items enabled, now has some items enabled, redraw *)
- EnableItem(gMenuGuides[menuIndex].theMenu, 0);
- mustRedraw := TRUE
- end;
-
- (* Update our copy of the enable flags *)
- gMenuGuides[menuIndex].enables := gMenuGuides[menuIndex].theMenu^^.enableFlags
- end;
-
- (* If at least one menu has changed state, must redraw the menu bar *)
- if mustRedraw then
- InvalMenuBar
- end;
-
- end.